package com.chunyu.app.utils;

import java.beans.IndexedPropertyDescriptor;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.commons.beanutils.BeanMap;
import org.apache.commons.beanutils.ContextClassLoaderLocal;
import org.apache.commons.beanutils.ConvertUtilsBean;
import org.apache.commons.beanutils.Converter;
import org.apache.commons.beanutils.DynaBean;
import org.apache.commons.beanutils.DynaClass;
import org.apache.commons.beanutils.DynaProperty;
import org.apache.commons.beanutils.MappedPropertyDescriptor;
import org.apache.commons.beanutils.PropertyUtilsBean;
import org.apache.commons.beanutils.converters.BigDecimalConverter;
import org.apache.commons.beanutils.converters.DoubleConverter;
import org.apache.commons.beanutils.converters.FloatConverter;
import org.apache.commons.beanutils.converters.IntegerConverter;
import org.apache.commons.beanutils.converters.LongConverter;
import org.apache.commons.beanutils.converters.ShortConverter;
import org.apache.commons.beanutils.converters.SqlDateConverter;
import org.apache.commons.beanutils.converters.SqlTimestampConverter;
import org.apache.commons.beanutils.converters.StringConverter;
import org.apache.commons.beanutils.expression.Resolver;
import org.apache.commons.lang3.reflect.MethodUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class BeanUtils {
	protected static Logger logger = LoggerFactory.getLogger(BeanUtils.class);

	/**
	 * 该方法将给定的所有对象参数列表转换合并生成一个Map，对于同名属性，依次由后面替换前面的对象属性
	 * 
	 * @param objs 对象列表
	 * @return 对于值为null的对象将忽略掉
	 */
	public static Map<String, Object> toMap(Object... objs) {
		Map<String, Object> map = new HashMap<String, Object>();
		for (Object object : objs) {
			if (object != null) {
				map.putAll(toMap(object));
			}
		}
		return map;
	}

	public static Map<String, Object> toMap(Object obj) {
		return toMap(obj, false);
	}

	/**
	 * 将对象转换成Map
	 *
	 * @param obj：要转换的对象
	 * @param filterNull：是否过滤过空值
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static Map<String, Object> toMap(Object obj, boolean filterNull) {
		Map<String, Object> map = new HashMap<String, Object>();
		if (obj == null) {
			return map;
		} else if (obj instanceof Map) {
			return (Map<String, Object>) obj;
		}
		BeanMap beanMap = new BeanMap(obj);
		Iterator<String> it = beanMap.keyIterator();
		while (it.hasNext()) {
			String name = it.next();
			Object value = beanMap.get(name);
			if (filterNull) {
				if (value != null) {
					map.put(name, value);
				}
			} else {
				map.put(name, value);
			}
		}
		return map;
	}

	/**
	 * 获取指定对象的Entity名称
	 */
	public static String getEntityName(Class<?> entityClass) {
		if (NullUtils.isNotEmpty(entityClass)) {
			String[] nameArray = entityClass.getName().split("[.]");
			return nameArray[nameArray.length - 1].trim();
		}
		return "";
	}

	public static List<Map<?, ?>> toMapList(List<?>... objs) {
		List<Map<?, ?>> list = new ArrayList<Map<?, ?>>();
		for (Object object : objs) {
			if (object != null) {
				List<?> listTemp = (List<?>) object;
				for (Object data : listTemp) {
					list.add(toMap(data));
				}
			}
		}
		return list;
	}

	/**
	 * 获取接口的泛型类型，如果不存在则返回null
	 */
	public static Class<?> getGenericClass(Class<?> clazz) {
		Type t = clazz.getGenericSuperclass();
		if (t instanceof ParameterizedType) {
			Type[] p = ((ParameterizedType) t).getActualTypeArguments();
			return ((Class<?>) p[0]);
		}
		return clazz;
	}

	/**
	 * 获取接口的泛型类型，如果不存在则返回null
	 */
	public static Class<?> getGenericClass(Class<?> clazz, int index) {
		Type t = clazz.getGenericSuperclass();
		if (t instanceof ParameterizedType) {
			Type[] p = ((ParameterizedType) t).getActualTypeArguments();
			if (p.length > index) {
				return ((Class<?>) p[index]);
			}
		}
		return null;
	}

	public static Object createInstance(Class<?> clazz, int index) {
		try {
			Class<?> entityClass = (Class<?>) getGenericClass(clazz, index);
			if (entityClass != null) {
				return entityClass.newInstance();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	public static Object createInstance(Class<?> clazz) {
		try {
			return clazz.newInstance();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	public static Object cloneBean(Object bean) throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException {
		return BeanUtilsBean.getInstance().cloneBean(bean);
	}

	public static boolean initCause(Throwable throwable, Throwable cause) {
		return BeanUtilsBean.getInstance().initCause(throwable, cause);
	}

	public static Object doInvoke(Object serviceObject, String methodName, Object... params) {
		try {
			return MethodUtils.invokeMethod(serviceObject, methodName, params);
		} catch (NoSuchMethodException e) {
			logger.error(serviceObject.getClass().getName() + "call [" + methodName + "] error:" + methodName);
			return null;
		} catch (IllegalAccessException | InvocationTargetException e) {
			logger.error(serviceObject.getClass().getName() + "call [" + methodName + "] error:" + methodName);
			return null;
		}

	}

	public static Object invoke(Object serviceObject, String methodName, Object... params) {
		try {
			return MethodUtils.invokeMethod(serviceObject, methodName, params);
		} catch (NoSuchMethodException e) {
			logger.error(serviceObject.getClass().getName() + "call [" + methodName + "] error:" + methodName, e);
			return null;
		} catch (IllegalAccessException | InvocationTargetException e) {
			logger.error(serviceObject.getClass().getName() + "call [" + methodName + "] error:" + methodName, e);
			return null;
		}

	}

	public static class BeanUtilsBean {
		@SuppressWarnings("rawtypes")
		private static final ContextClassLoaderLocal BEANS_BY_CLASSLOADER = new ContextClassLoaderLocal() {
			protected Object initialValue() {

				return new BeanUtilsBean();
			}
		};

		private ConvertUtilsBean convertUtilsBean;
		private PropertyUtilsBean propertyUtilsBean;
		private static final Method INIT_CAUSE_METHOD = getInitCauseMethod();
		static {
			getInstance().convertUtilsBean.register(new SqlDateConverter(null), java.sql.Date.class);
			getInstance().convertUtilsBean.register(new SqlDateConverter(null), java.util.Date.class);
			getInstance().convertUtilsBean.register(new DateTimeConverter(), java.util.Date.class);
			getInstance().convertUtilsBean.register(new SqlTimestampConverter(null), Timestamp.class);
			getInstance().convertUtilsBean.register(new LongConverter(null), Long.class);
			getInstance().convertUtilsBean.register(new StringConverter(null), String.class);
			getInstance().convertUtilsBean.register(new ShortConverter(null), Short.class);
			getInstance().convertUtilsBean.register(new IntegerConverter(null), Integer.class);
			getInstance().convertUtilsBean.register(new DoubleConverter(null), Double.class);
			getInstance().convertUtilsBean.register(new FloatConverter(null), Float.class);
			getInstance().convertUtilsBean.register(new BigDecimalConverter(null), BigDecimal.class);
		}

		public static BeanUtilsBean getInstance() {
			return (BeanUtilsBean) BEANS_BY_CLASSLOADER.get();
		}

		@SuppressWarnings("unchecked")
		public static void setInstance(BeanUtilsBean newInstance) {
			BEANS_BY_CLASSLOADER.set(newInstance);
		}

		public BeanUtilsBean() {
			this(new ConvertUtilsBean(), new PropertyUtilsBean());
		}

		public BeanUtilsBean(ConvertUtilsBean convertUtilsBean) {
			this(convertUtilsBean, new PropertyUtilsBean());
		}

		public BeanUtilsBean(ConvertUtilsBean convertUtilsBean, PropertyUtilsBean propertyUtilsBean) {
			this.convertUtilsBean = convertUtilsBean;
			this.propertyUtilsBean = propertyUtilsBean;
		}

		public Object cloneBean(Object bean) throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException {
			Object newBean = null;
			if ((bean instanceof DynaBean))
				newBean = ((DynaBean) bean).getDynaClass().newInstance();
			else {
				newBean = bean.getClass().newInstance();
			}
			getPropertyUtils().copyProperties(newBean, bean);
			return newBean;
		}

		public void copyProperties(Object dest, Object orig) throws IllegalAccessException, InvocationTargetException {
			if (dest == null) {
				throw new IllegalArgumentException("No destination bean specified");
			}

			if (orig == null) {
				throw new IllegalArgumentException("No origin bean specified");
			}
			if ((orig instanceof DynaBean)) {
				DynaProperty[] origDescriptors = ((DynaBean) orig).getDynaClass().getDynaProperties();

				for (int i = 0; i < origDescriptors.length; i++) {
					String name = origDescriptors[i].getName();

					if ((!getPropertyUtils().isReadable(orig, name)) || (!getPropertyUtils().isWriteable(dest, name)))
						continue;
					Object value = ((DynaBean) orig).get(name);
					copyProperty(dest, name, value);
				}
			} else if ((orig instanceof Map)) {
				@SuppressWarnings("unchecked")
				Iterator<Map.Entry<String, Object>> entries = ((Map<String, Object>) orig).entrySet().iterator();
				while (entries.hasNext()) {
					Map.Entry<String, Object> entry = entries.next();
					String name = (String) entry.getKey();
					try {
						if (getPropertyUtils().isWriteable(dest, name)) {
							copyProperty(dest, name, entry.getValue());
						}
					} catch (Exception e) {
					}
				}
			} else {
				PropertyDescriptor[] origDescriptors = getPropertyUtils().getPropertyDescriptors(orig);
				for (int i = 0; i < origDescriptors.length; i++) {
					String name = origDescriptors[i].getName();
					if ("class".equals(name)) {
						continue;
					}
					if ((!getPropertyUtils().isReadable(orig, name)) || (!getPropertyUtils().isWriteable(dest, name)))
						continue;
					try {
						Object value = getPropertyUtils().getSimpleProperty(orig, name);

						copyProperty(dest, name, value);
					} catch (NoSuchMethodException e) {
					}
				}
			}
		}

		public void copyProperty(Object bean, String name, Object value) throws IllegalAccessException, InvocationTargetException {

			Object target = bean;
			Resolver resolver = getPropertyUtils().getResolver();
			while (resolver.hasNested(name)) {
				try {
					target = getPropertyUtils().getProperty(target, resolver.next(name));
					name = resolver.remove(name);
				} catch (NoSuchMethodException e) {
					return;
				}
			}

			String propName = resolver.getProperty(name);
			Class<?> type = null;
			int index = resolver.getIndex(name);
			String key = resolver.getKey(name);

			if ((target instanceof DynaBean)) {
				DynaClass dynaClass = ((DynaBean) target).getDynaClass();
				DynaProperty dynaProperty = dynaClass.getDynaProperty(propName);
				if (dynaProperty == null) {
					return;
				}
				type = dynaProperty.getType();
			} else {
				PropertyDescriptor descriptor = null;
				try {
					descriptor = getPropertyUtils().getPropertyDescriptor(target, name);

					if (descriptor == null)
						return;
				} catch (NoSuchMethodException e) {
					return;
				}
				type = descriptor.getPropertyType();
				if (type == null) {
					return;
				}
			}
			if (index >= 0) {
				value = convert(value, type.getComponentType());
				try {
					getPropertyUtils().setIndexedProperty(target, propName, index, value);
				} catch (NoSuchMethodException e) {
					// logger.error("Cannot set {}", propName, e);
				}
			} else if (key != null) {
				try {
					getPropertyUtils().setMappedProperty(target, propName, key, value);
				} catch (NoSuchMethodException e) {
					// logger.info("Cannot set {}", propName);
				}
			} else {
				value = convert(value, type);
				try {
					getPropertyUtils().setSimpleProperty(target, propName, value);
				} catch (NoSuchMethodException e) {
					// logger.info("Cannot set {}", propName);
				}
			}
		}

		public String[] getArrayProperty(Object bean, String name) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
			Object value = getPropertyUtils().getProperty(bean, name);
			if (value == null)
				return null;
			if ((value instanceof Collection)) {
				ArrayList<Object> values = new ArrayList<Object>();
				Iterator<?> items = ((Collection<?>) value).iterator();
				while (items.hasNext()) {
					Object item = items.next();
					if (item == null) {
						values.add((String) null);
					} else {
						values.add(getConvertUtils().convert(item));
					}
				}
				return (String[]) (String[]) values.toArray(new String[values.size()]);
			}
			if (value.getClass().isArray()) {
				int n = Array.getLength(value);
				String[] results = new String[n];
				for (int i = 0; i < n; i++) {
					Object item = Array.get(value, i);
					if (item == null) {
						results[i] = null;
					} else {
						results[i] = getConvertUtils().convert(item);
					}
				}
				return results;
			}
			String[] results = new String[1];
			results[0] = getConvertUtils().convert(value);
			return results;
		}

		public String getIndexedProperty(Object bean, String name) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
			Object value = getPropertyUtils().getIndexedProperty(bean, name);
			return getConvertUtils().convert(value);
		}

		public String getIndexedProperty(Object bean, String name, int index) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
			Object value = getPropertyUtils().getIndexedProperty(bean, name, index);
			return getConvertUtils().convert(value);
		}

		public String getMappedProperty(Object bean, String name) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
			Object value = getPropertyUtils().getMappedProperty(bean, name);
			return getConvertUtils().convert(value);
		}

		public String getMappedProperty(Object bean, String name, String key) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
			Object value = getPropertyUtils().getMappedProperty(bean, name, key);
			return getConvertUtils().convert(value);
		}

		public String getNestedProperty(Object bean, String name) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
			Object value = getPropertyUtils().getNestedProperty(bean, name);
			return getConvertUtils().convert(value);
		}

		public String getProperty(Object bean, String name) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
			return getNestedProperty(bean, name);
		}

		public String getSimpleProperty(Object bean, String name) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
			Object value = getPropertyUtils().getSimpleProperty(bean, name);
			return getConvertUtils().convert(value);
		}

		public void populate(Object bean, Map<String, ?> properties) throws IllegalAccessException, InvocationTargetException {
			if ((bean == null) || (properties == null)) {
				return;
			}
			Iterator<?> entries = properties.entrySet().iterator();
			while (entries.hasNext()) {
				@SuppressWarnings("unchecked")
				Map.Entry<String, Object> entry = (Entry<String, Object>) entries.next();
				String name = entry.getKey();
				if (name == null) {
					continue;
				}

				setProperty(bean, name, entry.getValue());
			}
		}

		public void setProperty(Object bean, String name, Object value) throws IllegalAccessException, InvocationTargetException {
			Object target = bean;
			Resolver resolver = getPropertyUtils().getResolver();
			while (resolver.hasNested(name)) {
				try {
					target = getPropertyUtils().getProperty(target, resolver.next(name));
					name = resolver.remove(name);
				} catch (NoSuchMethodException e) {
					return;
				}
			}
			String propName = resolver.getProperty(name);
			Class<?> type = null;
			int index = resolver.getIndex(name);
			String key = resolver.getKey(name);

			if ((target instanceof DynaBean)) {
				DynaClass dynaClass = ((DynaBean) target).getDynaClass();
				DynaProperty dynaProperty = dynaClass.getDynaProperty(propName);
				if (dynaProperty == null) {
					return;
				}
				type = dynaProperty.getType();
			} else if ((target instanceof Map)) {
				type = Object.class;
			} else {
				PropertyDescriptor descriptor = null;
				try {
					descriptor = getPropertyUtils().getPropertyDescriptor(target, name);

					if (descriptor == null)
						return;
				} catch (NoSuchMethodException e) {
					return;
				}
				if ((descriptor instanceof MappedPropertyDescriptor)) {
					if (((MappedPropertyDescriptor) descriptor).getMappedWriteMethod() == null) {
						return;
					}
					type = ((MappedPropertyDescriptor) descriptor).getMappedPropertyType();
				} else if ((index >= 0) && ((descriptor instanceof IndexedPropertyDescriptor))) {
					if (((IndexedPropertyDescriptor) descriptor).getIndexedWriteMethod() == null) {
						return;
					}
					type = ((IndexedPropertyDescriptor) descriptor).getIndexedPropertyType();
				} else if (key != null) {
					if (descriptor.getReadMethod() == null) {
						return;
					}
					type = value == null ? Object.class : value.getClass();
				} else {
					if (descriptor.getWriteMethod() == null) {
						return;
					}
					type = descriptor.getPropertyType();
				}

			}

			Object newValue = null;
			if ((type.isArray()) && (index < 0)) {
				if (value == null) {
					String[] values = new String[1];
					values[0] = ((String) value);
					newValue = getConvertUtils().convert((String[]) values, type);
				} else if ((value instanceof String)) {
					newValue = getConvertUtils().convert(value, type);
				} else if ((value instanceof String[])) {
					newValue = getConvertUtils().convert((String[]) (String[]) value, type);
				} else {
					newValue = convert(value, type);
				}
			} else if (type.isArray()) {
				if (((value instanceof String)) || (value == null)) {
					newValue = getConvertUtils().convert((String) value, type.getComponentType());
				} else if ((value instanceof String[])) {
					newValue = getConvertUtils().convert(((String[]) (String[]) value)[0], type.getComponentType());
				} else {
					newValue = convert(value, type.getComponentType());
				}
			} else if (((value instanceof String)) || (value == null))
				newValue = getConvertUtils().convert((String) value, type);
			else if ((value instanceof String[])) {
				newValue = getConvertUtils().convert(((String[]) (String[]) value)[0], type);
			} else {
				newValue = convert(value, type);
			}

			try {
				getPropertyUtils().setProperty(target, name, newValue);
			} catch (NoSuchMethodException e) {
				throw new InvocationTargetException(e, "Cannot set " + propName);
			}
		}

		public ConvertUtilsBean getConvertUtils() {
			return this.convertUtilsBean;
		}

		public PropertyUtilsBean getPropertyUtils() {
			return this.propertyUtilsBean;
		}

		public boolean initCause(Throwable throwable, Throwable cause) {
			if ((INIT_CAUSE_METHOD != null) && (cause != null)) {
				try {
					INIT_CAUSE_METHOD.invoke(throwable, new Object[] { cause });
					return true;
				} catch (Throwable e) {
					return false;
				}
			}
			return false;
		}

		@SuppressWarnings({ "unchecked", "rawtypes" })
		protected Object convert(Object value, Class type) {
			Converter converter = getConvertUtils().lookup(type);

			if (converter != null && value != null) {
				return converter.convert(type, value);
			}
			return value;
		}

		@SuppressWarnings("rawtypes")
		private static Method getInitCauseMethod() {
			try {
				Class[] paramsClasses = { Throwable.class };
				return Throwable.class.getMethod("initCause", paramsClasses);
			} catch (NoSuchMethodException e) {
				return null;
			} catch (Throwable e) {
			}
			return null;
		}

		public Object getNextedPropertyObject(Object bean, String name) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
			Object value = getPropertyUtils().getNestedProperty(bean, name);
			return value;
		}

	}

	public static class DateTimeConverter implements Converter {
		@Override
		public <T> T convert(Class<T> type, Object value) {
			return toDate(type, value);
		}

		@SuppressWarnings("unchecked")
		public <T> T toDate(Class<T> type, Object value) {
			if (NullUtils.isEmpty(value)) {
				return null;
			} else if (value instanceof String) {
				String dateValue = value.toString().trim();
				if (type.equals(java.util.Date.class)) {
					return (T) DateUtils.str2Date(dateValue);
				} else {
					return null;
				}
			} else {
				return (T) value;
			}
		}
	}

	/**
	 * 获取obj对象fieldName的Field
	 * 
	 * @param target
	 * @param property
	 * @return
	 */
	public static Field getField(Object target, String property) {
		return getField(target.getClass(), property);
	}

	/**
	 * 获取obj对象fieldName的Field
	 */
	public static Field getField(Class<?> superClass, String property) {
		while (superClass != Object.class) {
			try {
				return superClass.getDeclaredField(property);
			} catch (NoSuchFieldException e) {
			}
			superClass = superClass.getSuperclass();
		}
		return null;
	}

	public static List<Field> getFields(Class<?> clazz) {
		return getFields(clazz, true);
	}

	/**
	 * 获取obj对象fieldName的Field
	 */
	public static List<Field> getFields(Class<?> clazz, boolean withSuperClass) {
		List<Field> fieldList = new ArrayList<Field>();
		while (clazz != Object.class) {
			for (Field field : clazz.getDeclaredFields()) {
				if (!Modifier.isStatic(field.getModifiers())) {
					fieldList.add(field);
				}
			}
			if (withSuperClass) {
				clazz = clazz.getSuperclass();
			} else {
				break;
			}
		}
		return fieldList;
	}

	/**
	 * 获取类的字段名信息
	 */

	public static List<String> getFieldNames(Class<?>... classValue) {
		return getFieldNames(true, classValue);
	}

	/**
	 * 获取类列表的相关字段信息
	 */
	public static List<String> getFieldNames(boolean withSuperClass, Class<?>... classValue) {
		List<String> result = new ArrayList<String>();
		for (Class<?> clazz : classValue) {
			List<Field> fields = getFields(clazz, withSuperClass);
			for (Field field : fields) {
				if (!result.contains(field.getName())) {
					result.add(field.getName());
				}
			}
		}
		return result;
	}

	/**
	 * 获取obj对象类型列表
	 *
	 */
	public static Map<String, String> getFieldsType(Class<?> superClass) {
		Map<String, String> mapping = new HashMap<String, String>();
		List<Field> fields = getFields(superClass);
		for (Field field : fields) {
			mapping.put(field.getName(), field.getGenericType().getTypeName());
		}
		return mapping;
	}

	/**
	 * 判读对象是否含有该属性
	 */
	public final static Object getProperty(Object params, String property) {
		if (params instanceof Map) {
			if (((Map<?, ?>) params).containsKey(property)) {
				return ((Map<?, ?>) params).get(property);
			} else {
				return null;
			}
		} else {
			try {
				Field field = getField(params, property);
				Object value = null;
				if (field != null) {
					if (field.isAccessible()) {
						value = field.get(params);
					} else {
						field.setAccessible(true);
						value = field.get(params);
						field.setAccessible(false);
					}
				}
				return value;
			} catch (Exception e) {
				return null;
			}
		}
	}

	/**
	 * * 拷贝,指定指属性列表拷贝
	 */
	public static void copy(Object newObject, Object oldObject, String... fields) {
		copy(newObject, oldObject, false, fields);
	}

	/**
	 * * 拷贝
	 */
	public static void copy(Object dest, Object orig) {
		copyProperties(dest, orig, true);
	}

	/**
	 * * 拷贝,忽略指定指属性列表
	 */
	public static void copy(Object newObject, Object oldObject, boolean filteNull, String... fields) {
		Map<String, Object> oldObjectMap = BeanUtils.toMap(oldObject);
		for (String key : fields) {
			try {
				if (filteNull) {
					if (NullUtils.isNotEmpty(oldObjectMap.get(key))) {
						BeanUtilsBean.getInstance().copyProperty(newObject, key, oldObjectMap.get(key));
					}
				} else {
					BeanUtilsBean.getInstance().copyProperty(newObject, key, oldObjectMap.get(key));
				}
			} catch (Exception e) {
				logger.debug("Bean copy", e);
			}
		}
	}

	/**
	 * * 拷贝,忽略指定指属性列表
	 */
	public static void copyProperties(Object dest, Object orig) {
		copyProperties(dest, orig, true);
	}

	/**
	 * * 拷贝,忽略指定指属性列表
	 * 
	 * @param dest
	 * @param orig
	 * @param copyNull
	 */
	public static void copyProperties(Object dest, Object orig, Boolean copyNull) {
		Map<?, ?> oldObjectMap = orig instanceof Map ? (Map<?, ?>) orig : toMap(orig, !copyNull);
		Set<?> fields = oldObjectMap.keySet();
		for (Object key : fields) {
			try {
				Object value = oldObjectMap.get(key);
				if (copyNull) {
					BeanUtils.setProperty(dest, key.toString(), value);
				} else if (NullUtils.isNotEmpty(value)) {
					BeanUtils.setProperty(dest, key.toString(), value);
				}
			} catch (Exception e) {
				logger.debug("Bean copyProperties:", e);
			}

		}
	}

	/**
	 * * 拷贝,忽略指定指属性列表
	 */
	public static void copyProperties(Object dest, Object orig, String... ignoreFileds) {
		Map<?, ?> oldObjectMap = orig instanceof Map ? (Map<?, ?>) orig : toMap(orig, false);
		Set<?> keySet = oldObjectMap.keySet();
		List<String> fileList = Arrays.asList(ignoreFileds);
		for (Object key : keySet) {
			if (!fileList.contains(key.toString())) {
				BeanUtils.setProperty(dest, key.toString(), oldObjectMap.get(key));
			}
		}
	}

	/**
	 * 判读对象是否含有该属性
	 */
	public final static <T> T getProperty(Object params, String property, Class<T> clazz) {
		Object obj = getProperty(params, property);
		return clazz.cast(obj);
	}

	@SuppressWarnings("unchecked")
	public final static <T> List<T> getArrayProperty(Object params, String property, Class<T> clazz) {
		Object obj = getProperty(params, property);
		if (obj == null) {
			return new ArrayList<T>();
		} else {
			return (List<T>) obj;
		}
	}

	public static Long getLongProperty(Object target, String property) {
		Object value = getProperty(target, property);
		if (value == null) {
			return null;
		}
		if (value instanceof Long) {
			return (Long) value;
		} else {
			return Long.valueOf(value.toString());
		}
	}

	public static Integer getIntegerProperty(Object target, String property) {
		Object value = getProperty(target, property);
		if (value == null) {
			return null;
		}
		if (value instanceof Integer) {
			return (Integer) value;
		} else {
			return Integer.valueOf(value.toString());
		}
	}

	public static Short getShortProperty(Object target, String property) {
		Object value = getProperty(target, property);
		if (value == null) {
			return null;
		}
		if (value instanceof Short) {
			return (Short) value;
		} else {
			return Short.valueOf(value.toString());
		}
	}

	public static Date getDateProperty(Object target, String property) {
		Object value = getProperty(target, property);
		if (value == null) {
			return null;
		}
		if (value instanceof Date) {
			return (Date) value;
		} else {
			return DateUtils.str2Date(value.toString());
		}
	}

	public static String getStringProperty(Object target, String property) {
		Object value = getProperty(target, property);
		if (value == null) {
			return null;
		}
		return value.toString();
	}

	/**
	 * 设置obj对象fieldName的属性值
	 */
	@SuppressWarnings("unchecked")
	public static void setProperty(Object target, String property, Object value) {
		if (target instanceof Map) {
			((Map<String, Object>) target).put(property, value);
		} else {
			try {

				Field field = getField(target, property);
				if (field == null) {
					return;
				}
				field.setAccessible(true);
				BeanUtilsBean.getInstance().setProperty(target, property, value);
			} catch (Exception e) {
				logger.error("setProperty:" + property, e);
			}
		}
	}

	/**
	 * 判读对象是否含有该属性
	 */
	public final static Boolean hasProperty(Object params, String property) {
		if (params instanceof Map) {
			return ((Map<?, ?>) params).containsKey(property);
		} else {
			return hasProperty(params.getClass(), property);
		}
	}

	public static boolean hasProperty(Class<?> target, String property) {
		try {
			Field field = getField(target, property);
			return (field == null) ? false : true;
		} catch (Exception e) {
			return false;
		}
	}

	/**
	 * 初始化对象
	 */
	public static final Object instantiate(String clazzName) {
		try {
			Class<?> clazz = Class.forName(clazzName);
			return clazz.newInstance();
		} catch (Exception e) {
			logger.error("instantiate", e);
		}
		return null;
	}

	public static final class ValueMapping {
		private Object name;
		private String title;
		private Object value;
		private Object oldValue;

		public Object getName() {
			return name;
		}

		public void setName(Object name) {
			this.name = name;
		}

		public Object getValue() {
			return value;
		}

		public void setValue(Object value) {
			this.value = value;
		}

		public Object getOldValue() {
			return oldValue;
		}

		public void setOldValue(Object oldValue) {
			this.oldValue = oldValue;
		}

		public ValueMapping() {
			super();
		}

		public String getTitle() {
			return title;
		}

		public void setTitle(String title) {
			this.title = title;
		}

		public ValueMapping(Object name, Object value, Object oldValue) {
			super();
			this.name = name;
			this.value = value;
			this.oldValue = oldValue;
		}

		public ValueMapping(Object name, String title, Object value, Object oldValue) {
			super();
			this.name = name;
			this.title = title;
			this.value = value;
			this.oldValue = oldValue;
		}

	}

	/**
	 * * 比较新旧对象属性变化
	 */
	public static List<ValueMapping> compare(Object newObj, Object oldObj, String... fileds) {
		List<String> fieldList = Arrays.asList(fileds);
		return compare(newObj, oldObj, fieldList);
	}

	public static List<ValueMapping> compare(Object newObj, Object oldObj) {
		return compare(newObj, oldObj, getFieldNames(newObj.getClass(), oldObj.getClass()));
	}

	public static List<ValueMapping> compare(Object newObj, Object oldObj, List<String> fields) {

		return compare(newObj, oldObj, fields, null);
	}

	public static List<ValueMapping> compare(Object newObj, Object oldObj, List<String> fields, Map<String, String> fieldsDesMap) {
		Map<?, ?> oldMap = oldObj instanceof Map ? (Map<?, ?>) oldObj : toMap(oldObj, false);
		Map<?, ?> newMap = newObj instanceof Map ? (Map<?, ?>) newObj : toMap(newObj, false);
		List<ValueMapping> result = new ArrayList<ValueMapping>();
		for (Object key : fields) {
			if (newMap.containsKey(key) || oldMap.containsKey(key)) {
				Object newValue = newMap.get(key), oldValue = oldMap.get(key);
				if (!EqualsUtils.equals(newValue, oldValue)) {
					if (NullUtils.isEmpty(fieldsDesMap) || !fieldsDesMap.containsKey(key)) {
						result.add(new ValueMapping(key, newMap.get(key), oldMap.get(key)));
					} else {
						result.add(new ValueMapping(key, fieldsDesMap.get(key), newMap.get(key), oldMap.get(key)));
					}
				}
			}
		}
		return result;
	}
}
